package xing.service.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.dingtalk.oapi.lib.aes.DingTalkEncryptException;
import com.dingtalk.oapi.lib.aes.DingTalkEncryptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import xing.application.api.Env;
import xing.application.service.isv.suite.CorpAuthService;
import xing.application.service.isv.suite.DingConfigService;
import xing.application.service.isv.suite.SuiteAuthService;
import xing.application.service.isv.suite.SuiteTicketService;
import xing.domain.isv.suite.LoginUser;
import xing.domain.isv.suite.Suite;
import xing.domain.isv.suite.enums.SuitePushType;
import xing.infrastructure.data.CallResult;
import xing.infrastructure.util.CookieUtil;
import xing.infrastructure.util.SymmetricEncoder;
import xing.domain.config.WebConsts;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.util.Map;

import static com.alibaba.fastjson.JSON.toJSON;

/*******************************************************************************************
 * 类描述：  
 *
 * @author: dustin
 * @date： 2017-8-18 19:33
 * @Description: 一句话描述该类的功能
 * @version 1.0.0
 *
 *
 * Version    Date       ModifiedBy                 Content  
 * -------- ---------    ----------         ------------------------  
 * 1.0.0     2017-8-18    Administrator                            
 *******************************************************************************************
 */
@RestController
@RequestMapping("/suite")
public class SuiteCallBackController {

    @Autowired
    SuiteAuthService suiteAuthService;
    @Autowired
    private SuiteTicketService suiteTicketService;
    @Autowired
    private CorpAuthService corpAuthService;
    @Autowired
    private DingConfigService dingConfigService;

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 创建套件的时候,回调地址就填写这个
     * @param signature
     * @param timestamp
     * @param nonce
     * @param json
     * @return
     */
    @RequestMapping(value = "/create", method = {RequestMethod.POST})
    public Map<String, String> suiteCreate(
            @RequestParam(value = "signature", required = false) String signature,
            @RequestParam(value = "timestamp", required = false) String timestamp,
            @RequestParam(value = "nonce", required = false) String nonce,
            @RequestBody(required = false) JSONObject json
    ) {
        try{
            /**
             * token,aseKey这两个参数在注册套件的时候,填写的。如果不想改代码,那么注册套件的时候也可以填写下面的两个数值
             * 要注意信息安全哦.
             */
            String token = "ISV2SUITE2Starpage2CN";
            String aseKey = "wy4kt7ps8hgefbff2ti07fwl9xixavxfyo9w5je95m1";
            DingTalkEncryptor dingTalkEncryptor = new DingTalkEncryptor(token, aseKey, Env.CREATE_SUITE_KEY);
            String encryptMsg = json.getString("encrypt");
            String plainText = dingTalkEncryptor.getDecryptMsg(signature, timestamp, nonce, encryptMsg);
            JSONObject callbackMsgJson = JSONObject.parseObject(plainText);
            String random = callbackMsgJson.getString("Random");
            String responseEncryMsg = random;
            Map<String, String> encryptedMap = dingTalkEncryptor.getEncryptedMap(responseEncryMsg, System.currentTimeMillis(), com.dingtalk.oapi.lib.aes.Utils.getRandomStr(8));
            return encryptedMap;
        }catch (Exception e){
            logger.error("创建套件失败",e);
            return null;
        }
    }

    /**
     * 当套件创建完毕之后,需要手动修改一下套件的回调地址。在修改套件的回调地址之前,需要在BD中插入一条记录
     *
     *  insert into isv_suite(id, gmt_create, gmt_modified, suite_name, suite_key, suite_secret, encoding_aes_key, token, event_receive_url)
     *  values(1, '2016-03-14 18:08:09', '2016-03-14 18:08:09', '服务报警应用', 'suitexdhgv7mnxxxxxxxx', 'xxxxxxxxxxKBJLLPtmFmwRtKfsuiEHHpBPx8jGlCSp-iznz9gFSpkG0T0KMU9jyB',
     *  'dd18qxxxxxx357g8r7itm5pyu5hg8ibe1blhqawhuaz', 'xxxxqaz2WSX', '');
     *
     * @param suiteKey
     * @param signature
     * @param timestamp
     * @param nonce
     * @param json
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/callback/{suiteKey}", method = {RequestMethod.POST})
    public  Map<String, String> receiveCallBack(@PathVariable("suiteKey") String suiteKey,
                                                @RequestParam(value = "signature", required = false) String signature,
                                                @RequestParam(value = "timestamp", required = false) String timestamp,
                                                @RequestParam(value = "nonce", required = false) String nonce,
                                                @RequestBody(required = false) JSONObject json
    ) {
        logger.info("进入套件回调事件 suiteKey:{},signature:{},timestamp:{},nonce:{}", suiteKey,signature,timestamp,nonce);

        Suite suite= suiteAuthService.getSuiteByKey(suiteKey);

        try{
            DingTalkEncryptor dingTalkEncryptor = new DingTalkEncryptor(suite.getToken(), suite.getEncodingAesKey(), suite.getSuiteKey());
            String encryptMsg = json.getString("encrypt");
            String plainText = dingTalkEncryptor.getDecryptMsg(signature,timestamp,nonce,encryptMsg);
            logger.info("解密之后明文消息 suiteKey:{},signature:{},timestamp:{},nonce:{},json:{},plainTest:{}",
                    suiteKey,signature,timestamp,nonce,json,plainText);

            //具体业务处理
            String returnStr = isvCallbackEvent(plainText,suiteKey);
            Map<String, String> encryptedMap = dingTalkEncryptor.getEncryptedMap(returnStr, System.currentTimeMillis(), com.dingtalk.oapi.lib.aes.Utils.getRandomStr(8));
            return encryptedMap;
        }catch (DingTalkEncryptException e){
            logger.error("解密失败程序异常",e);
        }catch (Exception e){
            logger.error("未知异常",e);
        }catch (Throwable throwable){
            logger.error("未知异常",throwable);
        }
        return null;
    }

    /**
     * 处理各种回调时间的TAG。这个维度的回调是和套件相关的
     * @param callbackMsg
     * @param suiteKey
     * @return
     */
    private String isvCallbackEvent(String callbackMsg,String suiteKey) {
        JSONObject callbackMsgJson = JSONObject.parseObject(callbackMsg);
        String eventType = callbackMsgJson.getString("EventType");
        String responseEncryMsg = "success";
        if(SuitePushType.SUITE_TICKET.getKey().equals(eventType)){
           /*"suite_ticket"事件每二十分钟推送一次,数据格式如下
				    {
					  "SuiteKey": "suitexxxxxx",
					  "EventType": "suite_ticket ",
					  "TimeStamp": 1234456,
					  "SuiteTicket": "adsadsad"
					}
				    */
            logger.info("进入suite_ticket事件");
            String suiteTicket = callbackMsgJson.getString("SuiteTicket");


            logger.info("获取的suite_ticket为"+suiteTicket);
                    /*
                     * ISV应当把最新推送的suiteTicket做持久化存储，
                     * 以防重启服务器之后丢失了当前的suiteTicket
                     *
                     */
            try {
                suiteTicketService.saveOrUpdateSuiteTicket(suiteKey,suiteTicket);
            } catch (Exception e) {
                logger.error("保存suite_ticket失败",e);
                responseEncryMsg = "faile";
            }
        }else if(SuitePushType.TMP_AUTH_CODE.getKey().equals(eventType)){
            String tmpAuthCode = callbackMsgJson.getString("AuthCode");

            CallResult r= suiteAuthService.saveOrUpdateSuiteAuth(suiteKey,tmpAuthCode);
            if(!r.isSuccess()){
                responseEncryMsg = "faile";
            }
        }else if(SuitePushType.CHANGE_AUTH.getKey().equals(eventType)){
            String corpId = callbackMsgJson.getString("AuthCorpId");
//            ServiceResult<Void>  sr = corpSuiteAuthService.handleChangeAuth(suiteKey,corpId);
//            if(!sr.isSuccess()){
//                responseEncryMsg = "faile";
//            }
        }else if(SuitePushType.SUITE_RELIEVE.getKey().equals(eventType)){
            String receiveCorpId = callbackMsgJson.getString("AuthCorpId");
            //解绑套件
            CallResult res = suiteAuthService.relieveAuth(suiteKey,receiveCorpId);
            if(!res.isSuccess()){
                responseEncryMsg = "faile";
            }
        }else if(SuitePushType.CHECK_CREATE_SUITE_URL.getKey().equals(eventType)){
            //TODO
        }else if(SuitePushType.CHECK_UPDATE_SUITE_URL.getKey().equals(eventType)){
            String random = callbackMsgJson.getString("Random");
            responseEncryMsg = random;
        }else if(SuitePushType.CHECK_SUITE_LICENSE_CODE.getKey().equals(eventType)){
            //TODO
            //留给业务自行判断
        }else{
            //当开放平台更新了新的推送类型,为了避免不认识,需要报警出来
//            bizLogger.error(LogFormatter.getKVLogData(LogFormatter.LogEvent.END,
//                    "无法识别的EventType",
//                    LogFormatter.KeyValue.getNew("suiteKey", suiteKey),
//                    LogFormatter.KeyValue.getNew("callbackMsg", callbackMsg)
//            ));
//            mainLogger.error(LogFormatter.getKVLogData(LogFormatter.LogEvent.END,
//                    "无法识别的EventType",
//                    LogFormatter.KeyValue.getNew("suiteKey", suiteKey),
//                    LogFormatter.KeyValue.getNew("callbackMsg", callbackMsg)
//            ));
        }
        return responseEncryMsg;
    }

    @GetMapping(value = "signback/{corpId}/{code}")
    public CallResult signback(@PathVariable("corpId") String corpId, @PathVariable("code") String code,
                               HttpServletRequest request, HttpServletResponse response){
        CallResult callResult;
        try {
            logger.info("enter signback corpId:{} code:{}",corpId,code);
//            LoginUser user=currentUserHelper.getCurrentUser(request);
//            if(user!=null){
//                logger.info("缓存取出用户:{}",user);
//                return CallResult.ok(user);
//            }

            LoginUser u= corpAuthService.getUserByAuthCode(corpId,code);
            logger.info("获取的用户:"+u);
            if(u!=null){
                String userJson= JSON.toJSONString(u);
                String encrypedJson= URLEncoder.encode(SymmetricEncoder.AESEncode(userJson),"utf-8");
                CookieUtil.addCookie(response,WebConsts.CurrentUser,encrypedJson,-1);
//                String sessionId=request.getSession().getId();
//                logger.info("jsessionId:{}",sessionId);
//                request.getSession().setAttribute(WebConsts.CurrentUser,u);

//                Cookie c=CookieUtil.getCookieByName(request,"Set-Cookie");
//                if(c==null){
//                    CookieUtil.addCookie(response,"Set-Cookie", "JSESSIONID="+ sessionId,0);
//                    request.getSession().setAttribute(WebConsts.CurrentUser,u);
//                }else{
//                    logger.info("jsession exist name:{} val:{}",c.getName(),c.getValue());
//                }


                //request.getSession().setMaxInactiveInterval(10000);
                logger.info("存入用户:{}",userJson);
            }
            return CallResult.ok(u);
        } catch (Exception e) {
            logger.error("获取当前用户失败",e);
            return CallResult.error(" 获取当前用户失败");
        }

    }
    /**
    * @Description: 测试使用
    * @param:  * @param null
    * @Author: dustin
    * @Date: 2017-9-11
    */
    @GetMapping(value = "signback1")
    public CallResult signback1(
                               HttpServletRequest request, HttpServletResponse response){
        CallResult callResult;
        try {

            LoginUser u= new LoginUser("1645","u8430978",false,1,"31654");
            logger.info("获取的用户:"+u);
            if(u!=null){
                String userJson= JSON.toJSONString(u);
                String encrypedJson= URLEncoder.encode(SymmetricEncoder.AESEncode(userJson),"utf-8");
                CookieUtil.addCookie(response,WebConsts.CurrentUser,encrypedJson,-1);
            }
            return CallResult.ok(u);
        } catch (Exception e) {
            logger.error("获取config失败",e);
            return CallResult.error(" 获取config失败");
        }

    }

    /**
     * 描    述：获取config
     * 创 建 人：陈天龙
     * 日    期：2017/8/28
     * @param corpId
     * @param appId
     * @return CallResult
     */
    @GetMapping(value = "config/{corpId}/{appId}")
    public CallResult getConfig(@PathVariable("appId") Long appId, @PathVariable("corpId") String corpId
            , HttpServletRequest request){
        CallResult callResult = null;
        try {
            String url = request.getHeader("referer");
            logger.info("获取的url为"+url);
            callResult = dingConfigService.getConfig(corpId,appId,url);
        } catch (Exception e) {
            callResult = CallResult.error("获取config失败");
            logger.error("获取config失败",e);
        }
        return callResult;
    }

}
